Windows几种sleep精度的测试,结果基于微秒

您所在的位置:网站首页 sleep200 sleep300 区别 Windows几种sleep精度的测试,结果基于微秒

Windows几种sleep精度的测试,结果基于微秒

2024-03-01 01:23| 来源: 网络整理| 查看: 265

Windows几种sleep精度的测试

在Windows环境下使用Sleep的时候,经常会遇到明明Sleep了1ms,结果被唤醒时所消耗的时间大于1ms,

对于那些精确度稍微高一点的Sleep控制时序,就不起作用了,众所周知Windows的Sleep是基于毫秒级别的,如果需要精确到微秒级,需要另辟蹊径

本文总结了几种常用的控制时序的方式,可以作为一个参考,测试出来的数值并不一定准确,我在我电脑上和另外一台Win7 i5 2.3GHz的电脑上跑出来的结果差别比较大,可以根据自己电脑或者使用环境多跑些数据

源码下载链接:0积分下载链接,没有积分的评论区留言,我改链接

测试类别分别包括:

    1、Windows中的原生Sleep

    2、C++11的this_thread::sleep_for以及timeBeginPeriod调整定时器精度两个方式

    3、socket连接的select的方式

    4、多媒体时钟QueryPerformanceCounter的微秒级方式

    5、MsgWaitForMultipleObjectsEx

系统环境:Win10,CPU i7-8750 2.2GHz

一、Sleep耗时

先上代码和测试结果

代码:

void Precision_Sleep() { std::string buffer; buffer.assign(BUFFER_SIZE, 0); buffer.clear(); int i = TEST_TIMES; uint64_t total_used = 0; while (i) { i--; steady_clock::time_point time_begin = steady_clock::now(); Sleep(Interval_Millisceonds); steady_clock::time_point time_end = steady_clock::now(); char tmp[128] = {0}; uint64_t used = duration_cast(time_end - time_begin).count(); snprintf(tmp, 128, "%s Sleep %d ms, time used : %lld us\n", __FUNCTION__, Interval_Millisceonds, used); total_used += used; buffer += tmp; } printf("%s\n", buffer.c_str()); printf("%s Sleep %d ms, avatar %lld us\n\n", __FUNCTION__, Interval_Millisceonds,total_used / TEST_TIMES); }

结果:

这是跑了50次的平均结果,Sleep(1),实际的平均sleep时间大约在1500微秒

二、C++11,sleep_for

代码:

void Precision_sleep_for() { std::string buffer; buffer.assign(BUFFER_SIZE, 0); buffer.clear(); int i = TEST_TIMES; uint64_t total_used = 0; while (i) { i--; steady_clock::time_point time_begin = steady_clock::now(); std::this_thread::sleep_for(microseconds(Interval_Microseconds)); steady_clock::time_point time_end = steady_clock::now(); char tmp[128] = {0}; uint64_t used = duration_cast(time_end - time_begin).count(); snprintf(tmp, 128, "%s Sleep %d us, time used : %lld us\n", __FUNCTION__, Interval_Microseconds, used); total_used += used; buffer += tmp; } printf("%s", buffer.c_str()); printf("%s Sleep %d us , avatar %lld us\n\n", __FUNCTION__, Interval_Microseconds, total_used / TEST_TIMES); }

结果:

sleep_for 1000us的平均时间也是在1500us左右

三、C++11 sleep_for 加上timeBeginPeriod

代码

void Precision_sleep_for_timeBeginPeriod() { // Test for sleep_for and timeBeginPeriod; std::string buffer; buffer.assign(BUFFER_SIZE, 0); buffer.clear(); int i = TEST_TIMES; uint64_t total_used = 0; while (i) { i--; steady_clock::time_point time_begin = steady_clock::now(); timeBeginPeriod(1);//set Minimum timer resolution. std::this_thread::sleep_for(microseconds(Interval_Microseconds)); timeEndPeriod(1); steady_clock::time_point time_end = steady_clock::now(); char tmp[128] = {0}; uint64_t used = duration_cast(time_end - time_begin).count(); snprintf(tmp, 128, "%s Sleep %d us , time used : %lld us\n", __FUNCTION__, Interval_Microseconds, used); total_used += used; buffer += tmp; } printf("%s", buffer.c_str()); printf("%s Sleep %d us , avatar %lld us\n\n", __FUNCTION__,Interval_Microseconds, total_used / TEST_TIMES); }

结果

 

无语。。。结果跟不加差不多。。。

四、select的方法

socket 中的select有个超时设置,据说这个超时设置是微秒级的,所以利用这点来测试.

代码

void SleepSelectUS(SOCKET s, int64_t usec) { struct timeval tv; fd_set dummy; FD_ZERO(&dummy); FD_SET(s, &dummy); tv.tv_sec = usec / 1000000L; tv.tv_usec = usec % 1000000L; select(0, 0, 0, &dummy, &tv); DWORD err = GetLastError(); if (err != 0) printf("Error : %d", err); } void Precision_select() { std::string buffer; buffer.assign(BUFFER_SIZE, 0); buffer.clear(); int i = TEST_TIMES; uint64_t total_used = 0; WORD wVersionRequested = MAKEWORD(1, 0); WSADATA wsaData; WSAStartup(wVersionRequested, &wsaData); SOCKET s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); while (i) { i--; steady_clock::time_point time_begin = steady_clock::now(); SleepSelectUS(s, Interval_Microseconds); steady_clock::time_point time_end = steady_clock::now(); char tmp[128] = {0}; uint64_t used = duration_cast(time_end - time_begin).count(); snprintf(tmp, 128, "%s Sleep %d us, time used : %lld us\n",__FUNCTION__, Interval_Microseconds, used); total_used += used; buffer += tmp; } closesocket(s); printf("%s", buffer.c_str()); printf("%s Sleep %d us, avatar %lld us\n\n", __FUNCTION__, Interval_Microseconds, total_used / TEST_TIMES); }

结果:

select的精度度稍微有所提高,平均时间为1017us,比上面两个精确一些,基本上可以达到我们的要求。

再看下500us和100us的

500微秒和100微秒的时间差不多,大致可以判断select的精度在500us左右。

五、多媒体时钟轮训的方式

代码

void SleepPerformUS(DWORD usec) { LARGE_INTEGER perfCnt, start, now; QueryPerformanceFrequency(&perfCnt); QueryPerformanceCounter(&start); do { QueryPerformanceCounter((LARGE_INTEGER*)&now); } while ((now.QuadPart - start.QuadPart) / float(perfCnt.QuadPart) * 1000 * 1000 < usec); } void Precision_QueryPerformanceCounter() { // Test for select; std::string buffer; buffer.assign(BUFFER_SIZE, 0); buffer.clear(); int i = TEST_TIMES; uint64_t total_used = 0; WORD wVersionRequested = MAKEWORD(1, 0); WSADATA wsaData; WSAStartup(wVersionRequested, &wsaData); SOCKET s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); while (i) { i--; steady_clock::time_point time_begin = steady_clock::now(); SleepPerformUS(Interval_Microseconds); steady_clock::time_point time_end = steady_clock::now(); char tmp[128] = {0}; uint64_t used = duration_cast(time_end - time_begin).count(); snprintf(tmp, 128, "%s Sleep 1000 us, time used : %lld us\n", __FUNCTION__, used); total_used += used; buffer += tmp; } closesocket(s); printf("%s", buffer.c_str()); printf("%s Sleep 1000 us, avatar %lld us\n\n", __FUNCTION__, total_used / TEST_TIMES); }

结果

喜出望外~sleep1000us所消耗的时间正好是我们需要的1000us!!!!是不是很心动??

再试试500us和100us的

但是!!!!!别高兴太早!!

从代码里面,我们可以看到这段代码:

do { QueryPerformanceCounter((LARGE_INTEGER*)&now); } while ((now.QuadPart - start.QuadPart) / float(perfCnt.QuadPart) * 1000 * 1000 < usec);

这就意味着,这种方式实现的Sleep是不停的在轮训,CPU一直在被占用,我在我的电脑上跑下来,这个轮训会消耗我8%的CPU

我是6核12线程,就意味着是单线程满负荷!

这个方式虽然好用,经不起CPU的消耗,也是没有办法满足我们需要的!

那些在推荐别人使用这种方式的人,不知道自己有没有使用这个代码,如果用在业务上了,我很佩服你们的产品!

六、MsgWaitForMultipleObjectsEx

代码:

void Precision_MsgWaitForMultipleObjectsEx() { std::string buffer; buffer.assign(BUFFER_SIZE, 0); buffer.clear(); int i = TEST_TIMES; uint64_t total_used = 0; while (i) { i--; steady_clock::time_point time_begin = steady_clock::now(); MsgWaitForMultipleObjectsEx(0, NULL, Interval_Millisceonds, QS_ALLPOSTMESSAGE, MWMO_INPUTAVAILABLE); steady_clock::time_point time_end = steady_clock::now(); char tmp[128] = {0}; uint64_t used = duration_cast(time_end - time_begin).count(); snprintf(tmp, 128, "%s Sleep %d ms, time used : %lld us\n", __FUNCTION__, Interval_Millisceonds, used); total_used += used; buffer += tmp; } printf("%s", buffer.c_str()); printf("%s Sleep %d us, avatar %lld ms\n\n", __FUNCTION__, Interval_Millisceonds, total_used / TEST_TIMES); }

结果:

MsgWaitForMultipleObjectsEx测试下来的时间浮动在1200us左右,最低的出现一次1060us,最高的跑到了1400+us,

 

综上所述,使用select的方式可以让我们的精度有所提高,相对于windows的Sleep和C++11的sleep_for,还是稍微有点提高,

后者时间这么接近,sleep_for的实现,不知道下面是不是就直接调用的Sleep。

另外有个高精度的方式,我没有做测试,从作者给出的时间来看也是很准的,有兴趣的也可以尝试一下

链接地址:高精度/微秒级线程的实现

 



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3